import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * WordNet
 */
public class WordNet {

    private Map<String, List<Integer>> synsetMap;
    private Map<Integer, String> synsetMapByID;
    private SAP sap;

    // constructor takes the name of the two input files
    public WordNet(String synsets, String hypernyms) {

        synsetMap = new HashMap<String, List<Integer>>();
        synsetMapByID = new HashMap<Integer, String>();
        int ctr = 0;

        int x=0;
        In in = new In(synsets);
        while (in.hasNextLine()) {
            String line = in.readLine();
            String[] fields = line.split(",");      //command delimited
            int id = Integer.parseInt(fields[0]);
            String[] synset = fields[1].split(" "); //space delimited
            for (String aSynset : synset) {
                List<Integer> ids = (synsetMap.containsKey(aSynset)? synsetMap.get(aSynset) : new ArrayList<Integer>());
                ids.add(id);
                synsetMap.put(aSynset, ids);       //lookup by Synset
            }
            synsetMapByID.put(id, synset[0]); //reverse lookup by ID,take 1st Synset
            ctr++;
        }
        in.close();

        Digraph d = new Digraph(ctr);

        In in2 = new In(hypernyms);
        while (in2.hasNextLine()) {
            String line = in2.readLine();
            String[] fields = line.split(",");
            Integer id = Integer.parseInt(fields[0]); //synset Id field is first
            for (int i=1; i<fields.length; i++) {     //subsequent fields hypernym
                Integer hypernymId = Integer.parseInt(fields[i]); //hypernymIds
                d.addEdge(id, hypernymId);
            }
        }
        in2.close();

        sap = new SAP(d);
    }

    // returns all WordNet nouns
    public Iterable<String> nouns() {
        return synsetMap.keySet();
    }

    // is the word a WordNet noun?
    public boolean isNoun(String word) {
        return synsetMap.containsKey(word);
    }

    // distance between nounA and nounB (defined below)
    public int distance(String nounA, String nounB)  {
        if (!isNoun(nounA) || !isNoun(nounB)) {
            throw new IllegalArgumentException();
        }
        return sap.length(synsetMap.get(nounA), synsetMap.get(nounB));
    }

    // a synset (second field of synsets.txt) that is the
    // common ancestor of nounA and nounB
    // in a shortest ancestral path (defined below)
    public String sap(String nounA, String nounB) {
        int ancestor = sap.ancestor(synsetMap.get(nounA), synsetMap.get(nounB));
        return synsetMapByID.get(ancestor);
    }

    // for unit testing of this class
    public static void main(String[] args) {
        WordNet w = new WordNet(args[0], args[1]);
        int dist = w.distance("Black_Plague", "black_marlin");
        StdOut.printf("dist = %d\n", dist);
        dist = w.distance("American_water_spaniel", "histology");
        StdOut.printf("dist = %d\n", dist);
        dist = w.distance("Brown_Swiss", "barrel_roll");
        StdOut.printf("dist = %d\n", dist);
        String ancestor = w.sap("individual", "edible_fruit");
        StdOut.printf("ancestor = %s\n", ancestor);

        dist = w.distance("horse", "table");
        StdOut.printf("dist = %d\n", dist);
    }
}